<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 
    Props:
      概念：一种特殊 attributes

      使用：
        1. 创建组件时需要通过 props 选项来声明
        2. 声明之后该 prop 可以像 data 数据一样直接在当前组件的模板中使用，也可以通过 this 访问到
        3. 在父组件模板中调用该组件时，需要在组件标签上传递 prop 下去。

      声明的语法：
        最简单的语法:
          props: ['prop1', 'prop2']

        高级语法：
          props: {
            prop1: Number, // 约定必须传递 number 类型的数据，否则会报错
            prop2: Array, // 数组
            prop3: String, // 字符串
            prop4: [Number, String], // 可以 数字 或 字符串
            prop5: Function, // 函数
            prop6: {
              type: Number, // 数字
              required: true, // 必须传递
              default: '', // 默认值，如果默认值是引用类型，那么需要写成函数返回的形式
            },
            prop7: {
              // 自定义校验，
              //  返回 true 表示校验通过
              //  返回 false 表示校验失败
              validator(value) {
                return 一个布尔值
              }
            }
          }

      Prop 默认值如果是对象或数组时为什么需要写成函数返回的形式：
      Vue2 中 data 选项为什么必须写成函数返回对象的形式：

          组件可以复用的，一个组件调用多次会产生多个组件实例，我们期望这多个实例之间不要互相影响，这时直接写成对象会让多个
          实例之间共享同一个内存地址，导致多个实例之间有污染。

   -->

    <div id="app"></div>

    <script src="../lib/vue3.js"></script>
    <script>
      const Root = {
        data() {
          return {
            person: {
              name: "张三",
              age: 18,
              gender: "男",
            },
          };
        },

        template: `
          <div>
            <h1>Root</h1>

            <hr />

            <Hello :name="'18'" :age="18" :sex="1" gender="女" />

            <Hello name="里斯" />

            <hr />

            <!-- 
              <World :name="person.name" :age="person.age" :gender="person.gender" />
            -->

            <World v-bind="person" />
          </div>
        `,
      };

      const Hello = {
        // props: ["name"],

        props: {
          name: {
            type: String,
            required: true,
          },
          age: {
            type: Number,
            default: 18,
          },
          sex: [Number, String],
          address: {
            type: Object,
            // 正确写法，通过函数返回引用类型
            default() {
              return {
                city: "深圳",
              };
            },

            // 错误写法
            // default: {
            //   city: "深圳",
            // },
          },
          gender: {
            validator(value) {
              // return value === "男" || value === "女";
              return ["男", "女"].includes(value);
            },
          },
        },

        computed: {
          reverseName() {
            return this.name.split("").reverse().join("");
          },
        },

        methods: {
          see() {
            console.log(this.address);
            this.address.city = "张三";
          },
        },

        template: `
          <div>
            <h2>Hello, {{ reverseName }}, {{ age }}, {{ address.city }}</h2>
            <button @click="see">查看 address</button>
          </div>
        `,
      };

      const World = {
        props: ["name", "age", "gender"],

        template: `
          <div>
            <h2>World - {{ name }}, {{ age }}, {{ gender }}</h2>
          </div>
        `,
      };

      // 创建应用实例
      const app = Vue.createApp(Root);

      // 创建全局组件
      app.component("Hello", Hello);
      app.component("World", World);

      // 挂载应用到挂载点
      app.mount("#app");
    </script>
  </body>
</html>
